package com.keehin;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;

import javax.swing.table.AbstractTableModel;

public class DBTableModel extends AbstractTableModel {

	private static final long serialVersionUID = 0L;

	private String[] colNames;

	private Class[] colTypes;

	private ResultSetMetaData rsmd;

	private ArrayList<Object[]> data;

	private boolean[] isEditables;

	private boolean haveId;

	private boolean isChecked;

	public DBTableModel() {
		colNames = new String[0];
		colTypes = new Class[0];
		data = new ArrayList<Object[]>();
		isEditables = new boolean[10];
	}

	public DBTableModel(ResultSet rs, boolean haveId, boolean isChecked) {
		this();
		this.setValues(rs, haveId, isChecked);
	}

	public void setValues(ResultSet rs, boolean haveId, boolean isChecked) {
		this.isChecked = isChecked;
		this.haveId = haveId;
		this.data.clear();
		try {
			this.rsmd = rs.getMetaData();
			int col = this.rsmd.getColumnCount() + 1;
			if (isChecked)
				col++; // for checked column
			this.colNames = new String[col];
			this.colTypes = new Class[colNames.length];
			this.colNames[0] = "ลำดับ";
			try {
				this.colTypes[0] = Class.forName("java.lang.Integer");
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			for (int i = 1; i <= this.rsmd.getColumnCount(); i++) {
				this.colNames[i] = this.rsmd.getColumnName(i);
				int type = this.rsmd.getColumnType(i);
				try {
					if (type == Types.INTEGER || type == Types.SMALLINT)
						this.colTypes[i] = Class.forName("java.lang.Integer");
					else if (type == Types.DOUBLE)
						this.colTypes[i] = Class.forName("java.lang.Double");
					else if (type == Types.FLOAT || type == Types.REAL
							|| type == 1112)
						this.colTypes[i] = Class.forName("java.lang.Float");
					else if (type == Types.BOOLEAN)
						this.colTypes[i] = Class.forName("java.lang.Boolean");
					else if (type == Types.DATE)
						this.colTypes[i] = Class.forName("java.util.Date");
					else
						this.colTypes[i] = Class.forName("java.lang.String");
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}

			}
			if (isChecked) {
				col--;
				if (haveId) {
					this.colNames[col] = this.colNames[col - 1];
					this.colTypes[col] = this.colTypes[col - 1];
					col--;
				}
				this.setEditable(col + 1);
				this.colNames[col] = "เลือก";
				try {
					this.colTypes[col] = Class.forName("java.lang.Boolean");
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
			int count = 0;
			Object[] record;
			int colCount = colNames.length;
			if (isChecked)
				colCount--;
			while (rs.next()) {
				record = new Object[colNames.length];
				record[0] = ++count;

				for (int i = 1; i < colCount; i++)
					record[i] = rs.getObject(i);

				if (isChecked) {
					int i = record.length - 1;
					if (haveId) {
						record[i] = record[i - 1];
						i--;
					}
					record[i] = new Boolean(false);
				}
				data.add(record);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	public Object getId(int rowIndex) {
		Object id = null;
		if (haveId)
			id = data.get(rowIndex)[colNames.length - 1];
		return id;
	}

	public String getColumnName(int col) {
		return colNames[col];
	}

	public int getColumnCount() {
		return haveId ? colNames.length - 1 : colNames.length;
	}

	public int getRowCount() {
		return data.size();
	}

	public Object getValueAt(int rowIndex, int columnIndex) {
		return data.get(rowIndex)[columnIndex];
	}

	public void setValueAt(Object value, int row, int col) {
		data.get(row)[col] = value;
		fireTableCellUpdated(row, col);
	}

	@SuppressWarnings("unchecked")
	public Class getColumnClass(int c) {
		return colTypes[c];
	}

	public boolean isCellEditable(int row, int col) {
		return this.isEditables[col];
	}

	public void setEditable(int col) {
		if (col > this.isEditables.length) {
			boolean[] arr = this.isEditables;
			this.isEditables = new boolean[isEditables.length * 2];
			System.arraycopy(arr, 0, this.isEditables, 0, arr.length);
		}
		this.isEditables[col - 1] = true;
	}

	public Object[] getArray(int row) {
		return data.get(row);
	}

	public boolean isChecked() {
		return isChecked;
	}
}
